home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 46 / Amiga Format CD46 (1999-10-20)(Future Publishing)(GB)[!][issue 1999-12].iso / -serious- / misc / dvi2tty-5.1 / dvistuff.c < prev    next >
C/C++ Source or Header  |  1999-09-06  |  42KB  |  1,444 lines

  1. /*
  2.  * Include files
  3.  */
  4.  
  5. #include "dvi2tty.h"
  6.  
  7. #if defined(VMS) 
  8. #include types.h
  9. #include stat
  10. #else
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #endif
  14.  
  15. #if defined(MSDOS)
  16. #include <math.h>
  17. #endif
  18.  
  19. #include "commands.h"
  20.  
  21.  
  22.  
  23. /*
  24.  * Constant definitions
  25.  */
  26.  
  27. #if defined(VMS) 
  28. #define mseek vmsseek
  29. #define ROUND(a)        (a>=0.0 ?  (int) (a + 0.5) : (int) (a - 0.5) )
  30. #else
  31. #define mseek fseek
  32. #endif
  33.  
  34. #define VERSIONID            2 /* dvi version number that pgm handles      */
  35. #define VERTICALEPSILON 450000L /* crlf when increasing v more than this   */
  36.  
  37. #define rightmargin     152    /* nr of columns allowed to the right of h=0*/
  38. #define leftmargin      -50    /* give some room for negative h-coordinate */
  39. #define LINELEN         203    /* rightmargin - leftmargin + 1 */
  40.  
  41. #define MOVE            TRUE   /* if advancing h when outputing a rule     */
  42. #define STAY            FALSE  /* if not advancing h when outputing a rule */
  43.  
  44. #define absolute        0      /* for seeking in files                     */
  45. #define relative        1
  46.  
  47. #define FORM             12    /* formfeed                                 */
  48. #define SPACE            32    /* space                                    */
  49. #define DEL             127    /* delete                                   */
  50.  
  51. #define LASTCHAR        127    /* max dvi character, above are commands    */
  52.  
  53. #define IMIN(a, b)      (a<b ? a : b)
  54. #define IMAX(a, b)      (a>b ? a : b)
  55.  
  56. #define get1()          num(1)
  57. #define get2()          num(2)
  58. #define get3()          num(3)
  59. #define get4()          num(4)
  60. #define sget1()         snum(1)
  61. #define sget2()         snum(2)
  62. #define sget3()         snum(3)
  63. #define sget4()         snum(4)
  64.  
  65.  
  66.  
  67. /*
  68.  * Structure and variable definitions
  69.  */
  70.  
  71. char *dvistuff = "@(#) dvistuff.c  5.10 23jul95 M.J.E. Mol (c) 1989-1995";
  72.  
  73. typedef struct {
  74.     long hh;
  75.     long vv;
  76.     long ww;
  77.     long xx;
  78.     long yy;
  79.     long zz;
  80. } stackitem;
  81.  
  82. typedef struct lineptr {        /* the lines of text to be output to outfile */
  83.     long            vv;                 /* vertical position of the line     */
  84.     int             charactercount;     /* pos of last char on line          */
  85.     struct lineptr *prev;               /* preceding line                    */
  86.     struct lineptr *next;               /* succeeding line                   */
  87.     char            text[LINELEN+1];    /* leftmargin...rightmargin          */
  88. } linetype;
  89.  
  90. typedef struct _font {
  91.     long    num;
  92.     struct _font * next;
  93.     char  * name;
  94. } font;
  95.  
  96.  
  97.  
  98. bool        pageswitchon;       /* true if user-set pages to print           */
  99. bool        sequenceon;         /* false if pagesw-nrs refers to TeX-nrs     */
  100. bool        scascii;            /* if true make Scand. nat. chars right      */
  101. bool        accent;             /* if true output accents etc: \'{e} etc.    */
  102. bool        ttfont = FALSE;     /* if true we assumed ttfonts, not cmr       */
  103. bool        symbolfont = FALSE; /* true if font is a symbol font             */
  104. bool        japan = FALSE;      /* switch to japanese fonts ...              */
  105. bool        mifont = FALSE;
  106. int         jfontnum = 0;
  107. bool        noffd;              /* if true output ^L instead of formfeed     */
  108.  
  109. int         opcode;             /* dvi-opcodes                               */
  110.  
  111. long        h, v;               /* coordinates, horizontal and vertical      */
  112. long        w, x, y, z;         /* horizontal and vertical amounts           */
  113.  
  114. long        pagecounter;        /* sequence page number counter              */
  115. long        backpointer;        /* pointer for offset to previous page       */
  116. long        pagenr;             /* TeX page number                           */
  117. int         stackmax;           /* stacksize required                        */
  118.  
  119. long        maxpagewidth;       /* width of widest page in file              */
  120. long        charwidth;          /* aprox width of character                  */
  121. long        lineheight = VERTICALEPSILON;
  122.                                 /* aprox height of a line                    */
  123.  
  124. linetype *  currentline;        /* pointer to current line on current page   */
  125. linetype *  firstline;          /* pointer to first line on current page     */
  126. linetype *  lastline;           /* pointer to last line on current page      */
  127. int         firstcolumn;        /* 1st column with something to print        */
  128.  
  129. stackitem * stack;              /* stack for dvi-pushes                      */
  130. int         sptr;               /* stack pointer                             */
  131.  
  132. font * fonts = NULL;            /* List of fontnames defined                 */
  133.  
  134.  
  135.  
  136. /*
  137.  * Function definitions
  138.  */
  139.  
  140. #if defined(MSDOS)
  141. void            postamble       (void);
  142. void            preamble        (void);
  143. void            walkpages       (void);
  144. void            initpage        (void);
  145. void            dopage          (void);
  146. void            skippage        (void);
  147. void            printpage       (void);
  148. bool            inlist          (long);
  149. void            rule            (bool, long, long);
  150. void            ruleaux         (long, long, char);
  151. long            horizontalmove  (long);
  152. int             skipnops        (void);
  153. linetype    *   getline         (void);
  154. linetype    *   findline        (void);
  155. unsigned long   num             (int);
  156. long            snum            (int);
  157. void            dochar          (char);
  158. void            symchar         (char);
  159. void            normchar        (char);
  160. void            outchar         (char);
  161. void            putcharacter    (long);
  162. void            setchar         (long);
  163. void            fontdef         (int);
  164. void            setfont         (long);
  165. void            jischar         (long);
  166. int             compute_jis     (int, int, int *, int *);
  167. int             getjsubfont     (char *);
  168.  
  169. #else
  170. void            postamble       (void);
  171. void            preamble        (void);
  172. void            walkpages       (void);
  173. void            initpage        (void);
  174. void            dopage          (void);
  175. void            skippage        (void);
  176. void            printpage       (void);
  177. bool            inlist          (long pagenr);
  178. void            rule            (bool moving, long rulewt, long ruleht);
  179. void            ruleaux         (long rulewt, long ruleht, char ch);
  180. long            horizontalmove  (long amount);
  181. int             skipnops        (void);
  182. linetype    *   getline         (void);
  183. linetype    *   findline        (void);
  184. unsigned long   num             (int size);
  185. long            snum            (int size);
  186. void            dochar          (char ch);
  187. void            symchar         (char ch);
  188. void            normchar        (char ch);
  189. void            outchar         (char ch);
  190. void            putcharacter    (long charnr);
  191. void            setchar         (long charnr);
  192. void            fontdef         (int x);
  193. void            setfont         (long fntnum);
  194. void            jischar         (long charnr);
  195. void            compute_jis     (int f, int c, int * ku, int * ten);
  196. int             getjsubfont     (char * s);
  197. #if defined(VMS)
  198. long        vmsseek        ();
  199. long        vms_ftell    ();
  200. long        vms_ungetc    ();
  201. #endif
  202. #endif
  203.  
  204.  
  205.  
  206. /*
  207.  * DVIMAIN -- The main function for processing the dvi file.
  208.  *            Here we assume there are to file pointers: DVIfile and output.
  209.  *            Also we have a list of pages pointed to by 'currentpage',
  210.  *            which is only used (in 'inlist()') when a page list is given.
  211.  */
  212.  
  213. void dvimain(void)
  214. {
  215.  
  216.     postamble();                            /* seek and process the postamble */
  217.     preamble();                             /* process preamble               */
  218.     /* note that walkpages *must* immediately follow preamble */
  219.     walkpages();                            /* time to do the actual work!    */
  220.  
  221.     return;
  222.  
  223. } /* dvimain */
  224.  
  225.  
  226.  /*
  227.   * POSTAMBLE -- Find and process postamble, use random access 
  228.   */
  229.  
  230. void postamble(void)
  231. {
  232.     register long size;
  233.     register int  count;
  234.     struct stat st;
  235.  
  236.     fstat (fileno(DVIfile), &st);
  237.     size = (long) st.st_size;                   /* get size of file          */
  238.     count = -1;
  239.     do {              /* back file up past signature bytes (223), to id-byte */
  240.         if (size-- == 0)
  241.             errorexit(nopst);
  242.         mseek(DVIfile, size, absolute);
  243.         opcode = (int) get1();
  244.         count++;
  245.     } while (opcode == TRAILER);
  246.     if (count < 4) {                            /* must have 4 trailer bytes */
  247.          foo = count;
  248.          errorexit(fwsgn);
  249.     }
  250.     if (opcode != VERSIONID)
  251.         errorexit(badid);
  252.     mseek(DVIfile, size-4, absolute);       /* back up to back-pointer       */
  253.     mseek(DVIfile, sget4(), absolute);      /* and to start of postamble     */
  254.     if (get1() != POST)
  255.         errorexit(nopst);
  256.     mseek(DVIfile, 20L, relative); /* lastpageoffset, numerator, denominator */
  257.                                    /* magnification, maxpageheight           */
  258.     maxpagewidth = sget4();
  259.     charwidth = maxpagewidth / (ttywidth + espace); 
  260.     stackmax = (int) get2();
  261.     if ((stack = (stackitem *) malloc(stackmax * sizeof(stackitem))) == NULL)
  262.        errorexit(stkrq);
  263.  
  264.     /* get2() -- totalpages */
  265.     /* fontdefs  do fontdefs in flight ... */
  266.  
  267.     return;
  268.  
  269. } /* postamble */
  270.  
  271.  
  272.  
  273. /*
  274.  * PREAMBLE --process preamble, use random access
  275.  */
  276.  
  277. void preamble(void)
  278. {
  279.  
  280.     mseek(DVIfile, 0L, absolute);       /* read the dvifile from the start   */
  281.     if ((opcode = skipnops()) != PRE)
  282.         errorexit(nopre);
  283.     opcode = (int) get1();        /* check id in preamble, ignore rest of it */
  284.     if (opcode != VERSIONID)
  285.         errorexit(badid);
  286.     mseek(DVIfile, 12L, relative);  /* numerator, denominator, magnification */
  287.     mseek(DVIfile, get1(), relative);         /* skip job identification     */
  288.  
  289.     return;
  290.  
  291. } /* preamble */
  292.  
  293.  
  294.  
  295. /*
  296.  * WALKPAGES -- process the pages in the DVI-file
  297.  */
  298.  
  299. void walkpages(void)
  300. {
  301.     register bool wantpage;
  302.  
  303.     pagecounter = 0L;
  304.     while ((opcode = skipnops()) != POST) {
  305.  
  306.         if (opcode != BOP)              /* should be at start of page now    */
  307.             errorexit(nobop);
  308.  
  309.         pagecounter++;
  310.         pagenr = sget4();               /* get TeX page number               */
  311.         mseek(DVIfile, 36L, relative);  /* skip page header */
  312.         backpointer = sget4();          /* get previous page offset          */
  313.         if (pageswitchon)
  314.             wantpage = inlist(sequenceon ? pagecounter : pagenr);
  315.         else
  316.             wantpage = TRUE;
  317.  
  318.         if (wantpage) {
  319.             initpage();
  320.             dopage();
  321.             printpage();
  322.         }
  323.         else
  324.                 skippage();
  325.     }
  326.  
  327.     return;
  328.  
  329. } /* walkpages */
  330.  
  331.  
  332.  
  333. /*
  334.  * INITPAGE -- Setup a new, empty page.
  335.  */
  336.  
  337. void initpage(void)
  338. {
  339.  
  340.     h = 0L;  v = 0L;                        /* initialize coordinates   */
  341.     x = 0L;  w = 0L;  y = 0L;  z = 0L;      /* initialize amounts       */
  342.     sptr = 0;                               /* initialize stack         */
  343.     currentline = getline();                /* initialize list of lines */
  344.     currentline->vv = 0L;
  345.     firstline   = currentline;
  346.     lastline    = currentline;
  347.     firstcolumn = rightmargin;
  348.     if (pageswitchon) {
  349.         if ((sequenceon ? pagecounter : pagenr) != firstpage->pag) 
  350.             if (noffd)
  351.                 fprintf(output, "^L\n");
  352.             else
  353.                 putc(FORM, output);
  354.     }
  355.     else
  356.         if (backpointer != -1)              /* not FORM at first page   */
  357.             if (noffd)
  358.                 fprintf(output, "^L\n");
  359.             else
  360.                 putc(FORM, output);
  361.  
  362.     return;
  363.  
  364. } /* initpage */
  365.  
  366.  
  367.  
  368. /*
  369.  * DOPAGE -- Process the dvi file until an end-off-page.
  370.  *           Build up a page image.
  371.  */
  372.  
  373. void dopage(void)
  374. {
  375.  
  376.     while ((opcode = (int) get1()) != EOP) {    /* process page until eop */
  377.         if (opcode <= LASTCHAR)
  378.             dochar((char) opcode);
  379.         else if ((opcode >= FONT_00) && (opcode <= FONT_63)) 
  380.             setfont(opcode - FONT_00);
  381.         else if (opcode > POST_POST)
  382.             errorexit(illop);
  383.         else
  384.             switch (opcode) {
  385.                 case SET1     : japan ? jischar(get1()) : setchar(get1());break;
  386.                 case SET2     : setchar(get2()); break;
  387.                 case SET3     : setchar(get3()); break;
  388.                 case SET4     : setchar(get4()); break;
  389.                 case SET_RULE : { long height = sget4();
  390.                                   rule(MOVE, sget4(), height); break;
  391.                                 }
  392.                 case PUT1     : putcharacter(get1()); break;
  393.                 case PUT2     : putcharacter(get2()); break;
  394.                 case PUT3     : putcharacter(get3()); break;
  395.                 case PUT4     : putcharacter(get4()); break;
  396.                 case PUT_RULE : { long height = sget4();
  397.                                   rule(STAY, sget4(), height); break;
  398.                                 }
  399.                 case NOP      : break;  /* no-op */
  400.                 case BOP      : errorexit(bdbop); break;
  401. /*              case EOP      : break;  strange place to have EOP */
  402.                 case PUSH     : if (sptr >= stackmax)            /* push */
  403.                                      errorexit(stkof);
  404.                                 stack[sptr].hh = h;
  405.                                 stack[sptr].vv = v;
  406.                                 stack[sptr].ww = w;
  407.                                 stack[sptr].xx = x;
  408.                                 stack[sptr].yy = y;
  409.                                 stack[sptr].zz = z;
  410.                                 sptr++;
  411.                                 break;
  412.                 case POP      : if (sptr-- == 0)                 /* pop */
  413.                                     errorexit(stkuf);
  414.                                 h = stack[sptr].hh;
  415.                                 v = stack[sptr].vv;
  416.                                 w = stack[sptr].ww;
  417.                                 x = stack[sptr].xx;
  418.                                 y = stack[sptr].yy;
  419.                                 z = stack[sptr].zz;
  420.                                 break;
  421.                 case RIGHT1   : (void) horizontalmove(sget1()); break;
  422.                 case RIGHT2   : (void) horizontalmove(sget2()); break;
  423.                 case RIGHT3   : (void) horizontalmove(sget3()); break;
  424.                 case RIGHT4   : (void) horizontalmove(sget4()); break;
  425.                 case W0       : h += w; break;
  426.                 case W1       : w = horizontalmove(sget1()); break;
  427.                 case W2       : w = horizontalmove(sget2()); break;
  428.                 case W3       : w = horizontalmove(sget3()); break;
  429.                 case W4       : w = horizontalmove(sget4()); break;
  430.                 case X0       : h += x; break;
  431.                 case X1       : x = horizontalmove(sget1()); break;
  432.                 case X2       : x = horizontalmove(sget2()); break;
  433.                 case X3       : x = horizontalmove(sget3()); break;
  434.                 case X4       : x = horizontalmove(sget4()); break;
  435.                 case DOWN1    : v += sget1(); break;
  436.                 case DOWN2    : v += sget2(); break;
  437.                 case DOWN3    : v += sget3(); break;
  438.                 case DOWN4    : v += sget4(); break;
  439.                 case Y0       : v += y; break;
  440.                 case Y1       : y = sget1(); v += y; break;
  441.                 case Y2       : y = sget2(); v += y; break;
  442.                 case Y3       : y = sget3(); v += y; break;
  443.                 case Y4       : y = sget4(); v += y; break;
  444.                 case Z0       : v += z; break;
  445.                 case Z1       : z = sget1(); v += z; break;
  446.                 case Z2       : z = sget2(); v += z; break;
  447.                 case Z3       : z = sget3(); v += z; break;
  448.                 case Z4       : z = sget4(); v += z; break;
  449.                 case FNT1     :
  450.                 case FNT2     :
  451.                 case FNT3     :
  452.                 case FNT4     : setfont(num(opcode - FNT1 + 1));
  453.                                 break;
  454.                 case XXX1     : mseek(DVIfile, get1(), relative); break;
  455.                 case XXX2     : mseek(DVIfile, get2(), relative); break;
  456.                 case XXX3     : mseek(DVIfile, get3(), relative); break;
  457.                 case XXX4     : mseek(DVIfile, get4(), relative); break;
  458.                 case FNT_DEF1 :
  459.                 case FNT_DEF2 :
  460.                 case FNT_DEF3 :
  461.                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1);
  462.                                 break;
  463.                 case PRE      : errorexit(bdpre); break;
  464.                 case POST     : errorexit(bdpst); break;
  465.                 case POST_POST: errorexit(bdpp); break;
  466.             }
  467.     }
  468.  
  469.     return;
  470.  
  471. } /* dopage */
  472.  
  473.  
  474.  
  475. /*
  476.  * SKIPPAGE -- Scan the dvi file until an end-off-page.
  477.  *             Skip this page.
  478.  */
  479.  
  480. void skippage(void)
  481. {
  482.     register int opcode;
  483.  
  484.     while ((opcode = (int) get1()) != EOP) {
  485.         if (opcode > POST_POST)
  486.             errorexit(illop);
  487.         else
  488.             switch (opcode) {
  489.                 case SET1     :
  490.                 case PUT1     :
  491.                 case RIGHT1   :
  492.                 case W1       :
  493.                 case X1       :
  494.                 case DOWN1    :
  495.                 case Y1       :
  496.                 case Z1       : /* assume FNT change can also be skipped */
  497.                 case FNT1     : mseek(DVIfile, 1L, relative); break;
  498.                 case SET2     :
  499.                 case PUT2     :
  500.                 case RIGHT2   :
  501.                 case W2       :
  502.                 case X2       :
  503.                 case DOWN2    :
  504.                 case Y2       :
  505.                 case Z2       :
  506.                 case FNT2     : mseek(DVIfile, 2L, relative); break;
  507.                 case SET3     :
  508.                 case PUT3     :
  509.                 case RIGHT3   :
  510.                 case W3       :
  511.                 case X3       :
  512.                 case DOWN3    :
  513.                 case Y3       :
  514.                 case Z3       :
  515.                 case FNT3     : mseek(DVIfile, 3L, relative); break;
  516.                 case SET4     :
  517.                 case PUT4     :
  518.                 case RIGHT4   :
  519.                 case W4       :
  520.                 case X4       :
  521.                 case DOWN4    :
  522.                 case Y4       :
  523.                 case Z4       :
  524.                 case FNT4     : mseek(DVIfile, 4L, relative); break;
  525.                 case SET_RULE :
  526.                 case PUT_RULE : mseek(DVIfile, 8L, relative); break;
  527.                 case BOP      : errorexit(bdbop); break;
  528.                 case XXX1     : mseek(DVIfile, get1(), relative); break;
  529.                 case XXX2     : mseek(DVIfile, get2(), relative); break;
  530.                 case XXX3     : mseek(DVIfile, get3(), relative); break;
  531.                 case XXX4     : mseek(DVIfile, get4(), relative); break;
  532.                 case FNT_DEF1 :
  533.                 case FNT_DEF2 :
  534.                 case FNT_DEF3 :
  535.                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1); break;
  536.                 case PRE      : errorexit(bdpre); break;
  537.                 case POST     : errorexit(bdpst); break;
  538.                 case POST_POST: errorexit(bdpp); break;
  539.         }
  540.     }
  541.  
  542.     return;
  543.  
  544. } /* skippage */
  545.  
  546.  
  547.  
  548. /*
  549.  * PRINTPAGE -- 'end of page', writes lines of page to output file 
  550.  */
  551.  
  552. void printpage(void)
  553. {
  554.     register int  i, j;
  555.     register char ch;
  556.  
  557.     if (sptr != 0)
  558.         fprintf(stderr, "dvi2tty: warning - stack not empty at eop.\n");
  559.     for (currentline = firstline; currentline != nil;
  560.           currentline = currentline->next) {
  561.         if (currentline != firstline) {
  562.             foo = ((currentline->vv - currentline->prev->vv)/lineheight)-1;
  563.             foo &= 3;            /* linespacings not too large */
  564.             for (i = 1; i <= (int) foo; i++)
  565.                 putc('\n', output);
  566.         }
  567.         if (currentline->charactercount >= leftmargin) {
  568.             foo = ttywidth - 2;
  569.             for (i = firstcolumn, j = 1; i <= currentline->charactercount;
  570.                    i++, j++) {
  571.                 ch = currentline->text[i - leftmargin];
  572.                 if (ch >= SPACE)
  573.                     putc(ch, output);
  574.                 if ((j > (int) foo) && (currentline->charactercount > i+1)) {
  575.                         fprintf(output, "*\n");         /* if line to large */
  576.                         fprintf(output, " *");          /* mark output      */
  577.                         j = 2;
  578.                 }
  579.             } 
  580.         }
  581.         putc('\n', output);
  582.     } 
  583.  
  584.     currentline = firstline;
  585.     while (currentline->next != nil) {
  586.         currentline = currentline->next;
  587.         free(currentline->prev);
  588.     }
  589.     free(currentline);              /* free last line */
  590.     currentline = nil;
  591.  
  592.     return;
  593.  
  594. } /* printpage */
  595.  
  596.  
  597.  
  598. /*
  599.  * INLIST -- return true if pagenr is in the list of pages to be printed.
  600.  */
  601.  
  602. bool inlist(long pagenr)
  603. {
  604.  
  605.     while ((currentpage->pag < 0) && (currentpage->pag != pagenr) &&
  606.            !currentpage->all && (currentpage->nxt != nil))
  607.         currentpage = currentpage->nxt;
  608.     if ((currentpage->all && (pagenr < currentpage->pag)) ||
  609.          (currentpage->pag == pagenr))
  610.             return TRUE;
  611.     else if (pagenr > 0) {
  612.         while ((currentpage->pag < pagenr) && (currentpage->nxt != nil))
  613.             currentpage = currentpage->nxt;
  614.         if (currentpage->pag == pagenr)
  615.             return TRUE;
  616.     }
  617.  
  618.     return FALSE;
  619.  
  620. } /* inlist */
  621.  
  622.  
  623.  
  624. /*
  625.  * RULE -- Output a rule (vertical or horizontal).
  626.  *         Increment h if moving is true.
  627.  */
  628.  
  629. void rule(bool moving, long rulewt, long ruleht)
  630. {
  631.  
  632.     register char ch;               /* character to set rule with            */
  633.     register long saveh, savev;
  634.                               /* rule   --   starts up the recursive routine */
  635.     if (!moving)
  636.         saveh = h;
  637.     if ((ruleht <= 0) || (rulewt <= 0))
  638.         h += rulewt;
  639.     else {
  640.         savev = v;
  641.         if ((ruleht / rulewt) > 0)         /* value < 1 truncates to 0 */
  642.             ch = '|';
  643.         else if (ruleht > (lineheight / 2))
  644.             ch = '=';
  645.         else
  646.             ch = '_';
  647.         ruleaux(rulewt, ruleht, ch);
  648.         v = savev;
  649.     }
  650.     if (!moving)
  651.         h = saveh;
  652.  
  653.     return;
  654.  
  655. } /* rule */
  656.  
  657.  
  658.  
  659. /*
  660.  * RULEAUX -- do the actual outtput for the rule recursively.
  661.  */
  662.  
  663. void ruleaux(long rulewt, long ruleht, char ch)
  664. {
  665.     register long wt, lmh, rmh;
  666.  
  667.     wt = rulewt;
  668.     lmh = h;                        /* save left margin                      */
  669.     if (h < 0) {                    /* let rules that start at negative h    */
  670.         wt -= h;                    /* start at coordinate 0, but let it     */
  671.         h = 0;                      /*   have the right length               */
  672.     }
  673.     while (wt > 0) {                /* output the part of the rule that      */
  674.         rmh = h;                    /*   goes on this line                   */
  675.         outchar(ch);
  676.         wt -= (h-rmh);              /* decrease the width left on line       */
  677.     }
  678.     ruleht -= lineheight;      /* decrease the height                   */
  679.     if (ruleht > lineheight) { /* still more vertical?                  */
  680.         rmh = h;                    /* save current h (right margin)         */
  681.         h = lmh;                    /* restore left margin                   */
  682.         v -= (lineheight + lineheight / 10);
  683.         ruleaux(rulewt, ruleht, ch);
  684.         h = rmh;                    /* restore right margin                  */
  685.     }
  686.  
  687.     return;
  688.  
  689. } /* ruleaux */
  690.  
  691.  
  692.  
  693. /*
  694.  * HORIZONTALMOVE -- Move the h pointer by amount.
  695.  */
  696.  
  697. long horizontalmove(long amount)
  698. {
  699.  
  700. #if defined(MSDOS)
  701.     if (labs(amount) > charwidth / 4L) {    /* } to make vi happy */
  702. #else
  703.     if (abs(amount) > charwidth / 4L) {
  704. #endif
  705.         foo = 3*charwidth / 4;
  706.         if (amount > 0)
  707.             amount = ((amount+foo) / charwidth) * charwidth;
  708.         else
  709. #if defined(VMS)
  710.             amount = (ROUND( (float) (amount-foo) / charwidth) + 1)* charwidth;
  711. #else
  712.             amount = ((amount-foo) / charwidth) * charwidth;
  713. #endif
  714.         h += amount;
  715.         return amount;
  716.     }
  717.     else
  718.         return 0;
  719.  
  720. }   /* horizontalmove */
  721.  
  722.  
  723.  
  724. /*
  725.  * SKIPNOPS -- Return first non NOP opcode.
  726.  */
  727.  
  728. int skipnops(void)
  729. {
  730.     register int opcode;
  731.  
  732.     while ((opcode = (int) num(1)) == NOP);
  733.  
  734.     return opcode;
  735.  
  736. } /* skipnops */
  737.  
  738.  
  739.  
  740. /*
  741.  * GETLINE -- Returns an initialized line-object 
  742.  */
  743.  
  744. linetype *getline(void)
  745. {
  746.     register int  i;
  747.     register linetype *temp;
  748.  
  749.     if ((temp = (linetype *) malloc(sizeof(linetype))) == NULL) 
  750.         errorexit(lnerq);
  751.     temp->charactercount = leftmargin - 1;
  752.     temp->prev = nil;
  753.     temp->next = nil;
  754.     for (i = 0; i < LINELEN; i++)
  755.         temp->text[i] = ' ';
  756.     temp->text[i] = '\0';
  757.  
  758.     return temp;
  759.  
  760. } /* getline */
  761.  
  762.  
  763.  
  764. /*
  765.  * FINDLINE -- Find best fit line were text should go
  766.  *             and generate new line if needed.
  767.  */
  768.  
  769. linetype *findline(void)
  770. {
  771.     register linetype *temp;
  772.     register long topd, botd;
  773.  
  774.     if (v <= firstline->vv) {                      /* above first line */
  775.         if (firstline->vv - v > lineheight) {
  776.             temp = getline();
  777.             temp->next = firstline;
  778.             firstline->prev = temp;
  779.             temp->vv = v;
  780.             firstline = temp;
  781.         }
  782.         return firstline;
  783.     }
  784.  
  785.     if (v >= lastline->vv) {                       /* below last line */
  786.         if (v - lastline->vv > lineheight) {
  787.             temp = getline();
  788.             temp->prev = lastline;
  789.             lastline->next = temp;
  790.             temp->vv = v;
  791.             lastline = temp;
  792.         }
  793.         return lastline;
  794.     }
  795.  
  796.     temp = lastline;                               /* in between two lines */
  797.     while ((temp->vv > v) && (temp != firstline))
  798.         temp = temp->prev;
  799.  
  800.     /* temp->vv < v < temp->next->vv --- temp is above, temp->next is below */
  801.     topd = v - temp->vv;
  802.     botd = temp->next->vv - v;
  803.     if ((topd < lineheight) || (botd < lineheight))
  804.         if (topd < botd)                           /* take best fit */
  805.             return temp;
  806.         else
  807.             return temp->next;
  808.  
  809.     /* no line fits suitable, generate a new one */
  810.     currentline = getline();
  811.     currentline->next = temp->next;
  812.     currentline->prev = temp;
  813.     temp->next->prev = currentline;
  814.     temp->next = currentline;
  815.     currentline->vv = v;
  816.  
  817.     return currentline;
  818.  
  819. } /* findline */
  820.  
  821.  
  822.  
  823. /*
  824.  * NUM --
  825.  */
  826.  
  827. unsigned long num(int size)
  828. {
  829.     register int i;
  830.     register long x = 0;
  831.  
  832.     for (i = size; i > 0; i--)
  833.         x = (x << 8) + (unsigned) getc(DVIfile);
  834.  
  835.     return x;
  836.  
  837. } /* num */
  838.  
  839.  
  840. /*
  841.  * SNUM --
  842.  */
  843.  
  844. long snum(int size)
  845. {
  846.     register int i;
  847.     register long x = 0;
  848.  
  849.     x = getc(DVIfile);
  850.     if (x & 0x80)
  851.         x -= 0x100;
  852.     for (i = size - 1; i > 0; i--)
  853.         x = (x << 8) + (unsigned) getc(DVIfile);
  854.  
  855.     return x;
  856.  
  857. } /* snum */
  858.  
  859.  
  860.  
  861. /*
  862.  * DOCHAR -- Process a character opcode.
  863.  */
  864.  
  865. void dochar(char ch)
  866. {
  867.  
  868.     if (japan && jfontnum)
  869.         jischar(ch);
  870.     else if (symbolfont == TRUE)
  871.         symchar(ch);
  872.     else
  873.         normchar(ch);
  874.  
  875.     return;
  876.  
  877. } /* dochar */
  878.  
  879.  
  880.  
  881. /*
  882.  * SYMCHAR -- Process a character opcode for a symbol font.
  883.  */
  884.  
  885. void symchar(char ch)
  886. {
  887.  
  888.     switch (ch) {       /* can do a lot more on MSDOS machines ... */
  889.        case   0: ch = '-'; break;
  890.        case   1: ch = '.'; break;
  891.        case   2: ch = 'x'; break;
  892.        case   3: ch = '*'; break;
  893.        case  13: ch = 'O'; break;
  894.        case  14: ch = 'O'; break;
  895.        case  15: ch = 'o'; break;
  896.        case  24: ch = '~'; break;
  897.        case  32: ch = japan ? '<' : 32; break; /* really only for japan? */
  898.        case  33: ch = japan ? '>' : 33; break; /* really only for japan? */
  899.        case 102: ch = '{'; break;
  900.        case 103: ch = '}'; break;
  901.        case 104: ch = '<'; break;
  902.        case 105: ch = '>'; break;
  903.        case 106: ch = '|'; break;
  904.        case 110: ch = '\\'; break;
  905.     }
  906.  
  907.     outchar(ch);
  908.  
  909.     return;
  910.  
  911. } /* symchar */
  912.  
  913.  
  914.  
  915. /*
  916.  * NORMCHAR -- Process a character opcode for a normal font.
  917.  */
  918.  
  919. void normchar(char ch)
  920. {
  921.  
  922.     switch (ch) {
  923.         case 11  :  if (ttfont) 
  924.                         ch = '^';                   /* up symbol       */
  925.                     else {
  926.                         outchar('f'); ch = 'f';     /* ligature        */
  927.                     }
  928.                     break;
  929.         case 12  :  if (ttfont) 
  930.                         ch = 'v';                   /* low symbol       */
  931.                     else {
  932.                         outchar('f'); ch = 'i';     /* ligature        */
  933.                     }
  934.                     break;
  935.         case 13  :  if (ttfont) 
  936.                         ch = '`';
  937.                     else {
  938.                         outchar('f'); ch = 'l';     /* ligature        */
  939.                     }
  940.                     break;
  941.         case 14  :  if (ttfont) 
  942.                         ch = 'i';                   /* spanish !        */
  943.                     else {
  944.                         outchar('f'); outchar('f');
  945.                                   ch = 'i';         /* ligature        */
  946.                     }
  947.                     break;
  948.         case 15  :  if (ttfont) 
  949.                         ch = '.';                   /* spanish ?        */
  950.                     else {
  951.                         outchar('f'); outchar('f');
  952.                                   ch = 'l';         /* ligature        */
  953.                     }
  954.                     break;
  955.         case 16  :  ch = 'i'; break;
  956.         case 17  :  ch = 'j'; break;
  957.         case 25  :  outchar('s'); ch = 's'; break;  /* German double s */
  958.         case 26  :  outchar('a'); ch = 'e'; break;  /* Dane/Norw ae    */
  959.         case 27  :  outchar('o'); ch = 'e'; break;  /* Dane/Norw oe    */
  960.         case 28  :  if (scascii)
  961.                         ch = '|';                   /* Dane/Norw /o    */
  962.                     else
  963.                         ch = 'o';
  964.                     break;
  965.         case 29  :  outchar('A'); ch = 'E'; break;  /* Dane/Norw AE    */
  966.         case 30  :  outchar('O'); ch = 'E'; break;  /* Dane/Norw OE    */
  967.         case 31  :  if (scascii)
  968.                         ch = '\\';                  /* Dane/Norw /O    */
  969.                     else
  970.                         ch = 'O';
  971.                     break;
  972.         case 32  :  ch = ttfont ? ch : '_'; break;  /* underlined blank */
  973.         case 58  :  ch = mifont ? '.' : ch; break;  /* if japan */
  974.         case 59  :  ch = mifont ? ',' : ch; break;  /* if japan */
  975.         case 92  :  ch = ttfont ? ch : '"'; break;  /* \ from `` */
  976.         case 123 :  ch = ttfont ? ch : '-'; break;  /* { from -- */
  977.         case 124 :  ch = ttfont ? ch : '_'; break;  /* | from --- */
  978.         case 125 :  ch = ttfont ? ch : '"'; break;  /* } from \H */
  979.         case 126 :  ch = ttfont ? ch : '"'; break;  /* ~ from \~ */
  980.         case 127 :  ch = '"'; break;  /* DEL from \" */
  981.        
  982.         /*
  983.          * Or should I use SPACE for non-accents ???
  984.          * This seems to work ...
  985.          */
  986.         case 18  :  ch = accent ? '`' : ch; break;  /* from \` */
  987.         case 19  :  ch = accent ? 0x27 : ch; break; /* from \' */
  988.         case 20  :  ch = accent ? '~' : ch; break;  /* from \v */
  989.         case 21  :  ch = accent ? '~' : ch; break;  /* from \u */
  990.         case 22  :  ch = accent ? '~' : ch; break;  /* from \= */
  991.         case 24  :  ch = accent ? ',' : ch; break;  /* from \c */
  992.         case 94  :  ch = (accent && !ttfont) ? '^' : ch; break;  /* ^ from \^ */
  993.         case 95  :  ch = (accent && !ttfont) ? '`' : ch; break;  /* _ from \. */
  994.     }
  995.     outchar(ch); 
  996.  
  997.     return;
  998.  
  999. } /* normchar */
  1000.  
  1001.  
  1002.  
  1003. /*
  1004.  * OUTCHAR -- Here we put the character into the current page.
  1005.  *            This function includes some code to handle Scandinavian
  1006.  *            characters. I think that code doesn'y belong here. IT
  1007.  *            SHOULD BE MOVED OUT.
  1008.  */
  1009.  
  1010. void outchar(char ch)
  1011. {
  1012.     register int i, j;
  1013.  
  1014. /*     fprintf(stderr, "hor: %ld, ver: %ld\n", h, v); */
  1015.  
  1016. #if defined(MSDOS)
  1017.     if (labs(v - currentline->vv) > lineheight / 2L)
  1018. #else
  1019.     if (abs(v - currentline->vv) > lineheight / 2L)
  1020. #endif
  1021.         currentline = findline();
  1022.  
  1023. #if 0
  1024.     j = (int) (((double) h / (double) maxpagewidth) * (ttywidth-1)) + 1;
  1025. #else
  1026.     j = (int) (h / charwidth);
  1027. #endif
  1028.     if (j > rightmargin)     /* leftmargin <= j <= rightmargin */
  1029.         j = rightmargin;
  1030.     else if (j < leftmargin)
  1031.         j = leftmargin;
  1032.     foo = leftmargin - 1;
  1033.  
  1034.     /*
  1035.      * This code does not really belong here ...
  1036.      *
  1037.      *-------------------------------------------------------------*
  1038.      * The following is very specialized code, it handles national *
  1039.      * Swe/Fin characters. They are respectively: a and o with two *
  1040.      * dots ("a & "o) and a with a circle (Oa). In Swe/Fin "ASCII" *
  1041.      * these characters replace {}|[] and \.  TeX outputs these by *
  1042.      * first issuing the dots or circle and then backspace and set *
  1043.      * the a or o. When dvi2tty finds an a or o it searches in the *
  1044.      * near vicinity for the character codes that represent circle *
  1045.      * or dots and if one is found the corresponding national char *
  1046.      * replaces the special character codes.                       *
  1047.      *-------------------------------------------------------------*/
  1048.     if (scascii) {
  1049.         if ((ch == 'a') || (ch == 'A') || (ch == 'o') || (ch == 'O')) {
  1050.             for (i = IMAX(leftmargin, j-2);
  1051.                  i <= IMIN(rightmargin, j+2);
  1052.                  i++)
  1053.                 if ((currentline->text[i - leftmargin] == 127) || /* DEL */
  1054.                     (currentline->text[i - leftmargin] == 34)  || /* "   */
  1055.                     (currentline->text[i - leftmargin] == 23))
  1056.                     foo = i;
  1057.             if (foo >= leftmargin) {
  1058.                 j = (int) foo;
  1059.                 switch (currentline->text[j - leftmargin]) {
  1060.                     case 127 :
  1061.                     case 34  :                         /* DEL or " */
  1062.                                if (ch == 'a')
  1063.                                    ch = '{';            /* } vi */
  1064.                                else if (ch == 'A')      /* dots ... */
  1065.                                    ch = '[';
  1066.                                else if (ch == 'o')
  1067.                                    ch = '|';
  1068.                                else if (ch == 'O')
  1069.                                    ch = '\\';
  1070.                                break;
  1071.                     case 23  : if (ch == 'a')
  1072.                                    ch = /* { vi */ '}';
  1073.                                else if (ch == 'A')      /* circle */
  1074.                                    ch = ']';
  1075.                                break;
  1076.                 }
  1077.             }
  1078.         }
  1079.     }
  1080.     /*----------------- end of 'Scandinavian code' ----------------*/
  1081.  
  1082.     if (foo == leftmargin-1)
  1083.         while ((currentline->text[j - leftmargin] != SPACE)
  1084.                && (j < rightmargin)) {
  1085.             j++;
  1086.             h += charwidth;
  1087.         }
  1088.     if ( ((ch >= SPACE) && (ch != DEL)) ||
  1089.          (scascii && (ch == 23)) ) {
  1090.           /*  (scascii && (ch == DEL)) )     if VMS ??? */
  1091.         if (j < rightmargin)
  1092.             currentline->text[j - leftmargin] = ch;
  1093.         else
  1094.             currentline->text[rightmargin - leftmargin] = '@';
  1095.         if (j > currentline->charactercount)
  1096.             currentline->charactercount = j;
  1097.         if (j < firstcolumn)
  1098.             firstcolumn = j;
  1099.     }
  1100.     h += charwidth;
  1101.  
  1102.     return;
  1103.  
  1104. } /* outchar */
  1105.  
  1106.  
  1107.  
  1108. /*
  1109.  * PUTCHARACTER -- Output character, don't change h 
  1110.  */
  1111.  
  1112. void putcharacter(long charnr)
  1113. {
  1114.     register long saveh;
  1115.  
  1116.     saveh = h;
  1117.     if (japan)
  1118.         dochar(charnr);
  1119.     else if ((charnr >= 0) && (charnr <= LASTCHAR))
  1120.         outchar((char) charnr);
  1121.     else
  1122.         setchar(charnr);
  1123.     h = saveh;
  1124.  
  1125.     return;
  1126.  
  1127. } /* putcharacter */
  1128.  
  1129.  
  1130.  
  1131. /*
  1132.  * SETCHAR -- Should print characters with character code>127 from
  1133.  *            current font. Note that the parameter is a dummy, since
  1134.  *            ascii-chars are<=127.
  1135.  */
  1136.  
  1137. void setchar(long charnr)
  1138. {
  1139.  
  1140.     outchar('#');
  1141.  
  1142.     return;
  1143.  
  1144. } /* setchar */
  1145.  
  1146.  
  1147.  
  1148. /*
  1149.  * FONTDEF -- Process a font definition.
  1150.  */
  1151.  
  1152. void fontdef(int x)
  1153. {
  1154.     register int i;
  1155.     char * name;
  1156.     font * fnt;
  1157.     int namelen;
  1158.     long fntnum;
  1159.     int new = 0;
  1160.  
  1161.     fntnum = num(x);
  1162.     (void) get4();                      /* checksum */
  1163.     (void) get4();                      /* scale */
  1164.     (void) get4();                      /* design */
  1165.     namelen = (int) get1() + (int) get1();
  1166.     fnt = fonts;
  1167.     while (fnt != NULL && fnt->num != fntnum)       /* does fontnum exist */
  1168.         fnt = fnt->next;
  1169.     if (fnt == NULL) {
  1170.         if ((fnt = (font *) malloc(sizeof(font))) == NULL) {
  1171.             perror("fontdef");
  1172.             exit(1);
  1173.         }
  1174.         fnt->num = fntnum;
  1175.         new = 1;
  1176.     }
  1177.     else
  1178.         free(fnt->name);    /* free old name */
  1179.     if ((name = (char *) malloc((namelen+1) * sizeof(char))) == NULL) {
  1180.         perror("fontdef");
  1181.         exit(1);
  1182.     }
  1183.     
  1184.     for (i = 0; i < namelen; i++)
  1185.         name[i] = get1();
  1186.     name[i] = '\0';    /* just to be sure */
  1187.     fnt->name = name;
  1188.     if (new) {
  1189.         fnt->next = fonts;
  1190.         fonts = fnt;
  1191.     }
  1192.  
  1193.     return;
  1194.  
  1195. } /* fontdef */
  1196.  
  1197.  
  1198.  
  1199. /*
  1200.  * SETFONT -- Switch to specific font. Try to find out if it is a symbol
  1201.  *            font.
  1202.  */
  1203.  
  1204. void setfont(long fntnum)
  1205. {
  1206.     font * fnt;
  1207.     char * s;
  1208.  
  1209.     fnt = fonts;
  1210.     while (fnt != NULL && fnt->num != fntnum)
  1211.         fnt = fnt->next;
  1212.     symbolfont = FALSE;
  1213.     ttfont = FALSE;
  1214.     mifont = FALSE;
  1215.     jfontnum = 0;
  1216.     if (fnt == NULL) {
  1217.         /* error : font not found */
  1218.         return;
  1219.     }
  1220.  
  1221.     s = fnt->name;
  1222.     if (japan)
  1223.         jfontnum = getjsubfont(s);
  1224.     if (jfontnum == 0) {
  1225.         while ((s = strchr(s, 's')) != NULL) {
  1226.             if (strncmp("sy", s, 2) == 0) {
  1227.                 symbolfont = TRUE;
  1228.                 break;
  1229.             }
  1230.         s++;      /* New line to fix bug; font names with 's' would hang */
  1231.         }
  1232.    
  1233.         s = fnt->name;
  1234.         while ((s = strchr(s, 't')) != NULL) {
  1235.             if (strncmp("tt", s, 2) == 0) {
  1236.                 ttfont = TRUE;
  1237.                 break;
  1238.             }
  1239.         s++;      /* New line to fix bug; font names with 's' would hang */
  1240.         }
  1241.    
  1242.         s = fnt->name;
  1243.         while ((s = strchr(s, 'm')) != NULL) {
  1244.             if (strncmp("mi", s, 2) == 0) {
  1245.                 mifont = TRUE;
  1246.                 break;
  1247.             }
  1248.         s++;      /* New line to fix bug; font names with 's' would hang */
  1249.         }
  1250.     }
  1251.    
  1252.  
  1253.     return;
  1254.  
  1255. } /* setfont */
  1256.  
  1257.  
  1258.  
  1259. void jischar(long charnr)
  1260. {
  1261.     int Ku,Ten;
  1262.  
  1263.     compute_jis(jfontnum, charnr, &Ku, &Ten);
  1264.     outchar(Ku+128);
  1265.     outchar(Ten+128);
  1266.  
  1267.     return;
  1268.  
  1269. } /* jischar */
  1270.   
  1271. #define    kushift(c)    c+0x20
  1272. #define    tenshift(c)    c+0x20
  1273.  
  1274. void compute_jis(int f, int c, int *ku, int *ten)
  1275. {
  1276.     int n;
  1277.  
  1278.     if (f <= 7) {
  1279.         if (f == 1) {
  1280.             if (c >= 100) {
  1281.                 *ku = kushift(2);
  1282.                 *ten = tenshift(c-100);
  1283.             }
  1284.             else {
  1285.                 *ku = kushift(1);
  1286.                 *ten = tenshift(c);
  1287.             }
  1288.         }
  1289.         else if (f == 2) {
  1290.             *ku = kushift(3);
  1291.             *ten = tenshift(c-32);
  1292.         }
  1293.         else {
  1294.             *ku = kushift(f+1);
  1295.             *ten = tenshift(c);
  1296.         }
  1297.     }
  1298.     else if (f <= 19) {    /* Daiichi Suijun */
  1299.         n = (f-8)*256+c;
  1300.         *ku = kushift((n/94)+16);
  1301.         *ten = tenshift((n%94)+1);
  1302.     }
  1303.     else {            /* Daini Suijun */
  1304.         n = (f-20)*256+c;
  1305.         *ku = kushift((n/94)+48);
  1306.         *ten = tenshift((n%94)+1);
  1307.     }
  1308.  
  1309.     return;
  1310.  
  1311. } /* compute_jis */
  1312.  
  1313.  
  1314. #define    NJSUBS        33
  1315. char *jsf_names[]={
  1316.     "jsy", "jroma", "jhira", "jkata", "jgreek", "jrussian", "jkeisen",
  1317.     "jka", "jkb", "jkc", "jkd", "jke", "jkf", "jkg", "jkh", "jki", "jkj",
  1318.     "jkk", "jkl", "jkm", "jkn", "jko", "jkp", "jkq", "jkr", "jks", "jkt",
  1319.     "jku", "jkv", "jkw", "jkx", "jky", "jkz"
  1320. };
  1321.  
  1322.  
  1323. int getjsubfont(char *s)
  1324. {
  1325.     int jf;
  1326.  
  1327.     if (s[0] == 'd' && (s[1] == 'm' || s[1] == 'g')) {
  1328.         for (jf = 0; jf < NJSUBS; jf++) {
  1329.             if (strncmp(&s[2], jsf_names[jf], strlen(jsf_names[jf])) == 0) 
  1330.                 return jf+1;
  1331.         }
  1332.         return 0;
  1333.     }
  1334.     else
  1335.       return 0;
  1336.  
  1337. } /* getjsubfont */
  1338.  
  1339.    
  1340.  
  1341.  
  1342. /* 
  1343.  * VMS CODE 
  1344.  */
  1345.  
  1346. #if defined(VMS)
  1347. long vmsseek(fp,n,dir)
  1348. FILE *fp;
  1349. long n;
  1350. long dir;
  1351. {
  1352.     long k,m,pos,val,oldpos;
  1353.     struct stat buffer;
  1354.  
  1355.     for (;;) {                     /* loops only once or twice */
  1356.         switch (dir) {
  1357.             case 0:            /* from BOF */
  1358.                     oldpos = vms_ftell(fp);
  1359.                     k = n & 511;
  1360.                     m = n >> 9;
  1361.                     if (((*fp)->_cnt) && ((oldpos >> 9) == m)) {
  1362.                         val = 0; /* still in */
  1363.                         (*fp)->_ptr = ((*fp)->_base) + k;
  1364.                         (*fp)->_cnt = 512 - k;
  1365.                     }
  1366.                     else {
  1367.                         val = fseek(fp, m << 9, 0);
  1368.                         if (val == 0) {
  1369.                             (*fp)->_cnt = 0;
  1370.                             (void) fgetc(fp);
  1371.                             (*fp)->_ptr = ((*fp)->_base) + k;
  1372.                             (*fp)->_cnt = 512 - k;
  1373.                         }
  1374.                     }
  1375.                     return(val);
  1376.  
  1377.             case 1: pos = vms_ftell(fp);
  1378.                     if (pos == EOF)
  1379.                         return (EOF);
  1380.                     n += pos;
  1381.                     dir = 0;
  1382.                     break;
  1383.  
  1384.             case 2: val = fstat(fileno(fp), &buffer);
  1385.                     if (val == EOF)
  1386.                         return (EOF);
  1387.                     n += buffer.st_size - 1;
  1388.  
  1389.                     dir = 0;
  1390.                     break;
  1391.  
  1392.             default : return (EOF);
  1393.         }
  1394.     }
  1395.  
  1396.     /* NOTREACHED */
  1397.  
  1398. } /* vmsseek */
  1399.         
  1400.  
  1401.  
  1402. long vms_ftell(fp)
  1403. FILE *fp;
  1404. {
  1405.     char c;
  1406.     long pos;
  1407.     long val;
  1408.  
  1409.     if ((*fp)->_cnt == 0) {
  1410.         c = fgetc(fp);
  1411.         val = vms_ungetc(c, fp);
  1412.         if (val != c)
  1413.             return (EOF);
  1414.     }
  1415.     pos = ftell(fp);
  1416.     if (pos >= 0)
  1417.         pos += ((*fp)->_ptr) - ((*fp)->_base);
  1418.  
  1419.     return (pos);
  1420.  
  1421. } /* vms_ftell */
  1422.  
  1423.  
  1424.  
  1425. long vms_ungetc(c,fp)
  1426. char c;
  1427. FILE *fp;
  1428. {
  1429.  
  1430.     if ((c == EOF) && feof(fp))
  1431.         return (EOF);
  1432.  
  1433.     if ((*fp)->_cnt >= 512)
  1434.         return (EOF);
  1435.     
  1436.     (*fp)->_cnt++;
  1437.     (*fp)->_ptr--;
  1438.     *((*fp)->_ptr) = c;
  1439.  
  1440.     return (c);
  1441.  
  1442. } /*vms_ungetc */
  1443. #endif
  1444.